import { CheckUtil } from "./check";
import { MathUtil } from "./math";
import { StringUtil } from "./string";

/** 数值相关包 **/
export const NumberUtil = {
  /** c语言中32位int型数据运算的最大安全数字，用于接口获取所有数据情况 **/
  MAX_PAGE_SIZE: 2147483647,

  /**
   * 查看数值是否超出位数限制
   * @param num
   * @param int
   * @param float
   * @returns {boolean}
   */
  isBeyond(num, int, float) {
    const numStr = String(num);

    if (numStr.indexOf("e+") >= 0) {
      return parseFloat(numStr.split("e+")[1]) > int;
    }

    if (numStr.indexOf("e-") >= 0) {
      return parseFloat(numStr.split("e-")[1]) < float;
    }

    const [a = "", b = ""] = numStr.split(".");

    return a.length > int || b.length > float;
  },

  /**
   * 精确数值格式化
   * @param num
   * @param ratio
   * @param isZeroShowNull 数值为零时，显示为空
   * @returns {string}
   */
  toFixed(num, ratio, isZeroShowNull = false) {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }

    if (!CheckUtil.isLikeNumber(ratio)) {
      return num;
    }

    const roundNum = MathUtil.round(num, ratio) || 0;
    return isZeroShowNull && roundNum === 0 ? null : roundNum.toFixed(ratio);
  },

  /**
   * 精确数值格式化后的数值
   * @param num
   * @param ratio
   * @returns {number}
   */
  toFixedNumber(num, ratio) {
    return parseFloat(this.toFixed(num, ratio)) || 0;
  },

  /**
   * 精确数值格式化后的带货币单位数值
   * @param num
   * @param ratio
   * @param moneyUnit < ¥ $ >
   * @returns {string}
   */
  toFixedMoney(num, ratio, moneyUnit = "¥") {
    return `${moneyUnit}${this.toFixed(num, ratio) || 0}`;
  },

  /**
   * 精确数值格式化，带单位
   * @param num
   * @param ratio
   * @returns {string}
   */
  toFixedUnit(num, ratio = 2) {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }

    const len = num.toString().length;
    if (len > 8) {
      return this.toFixed(MathUtil.divide(num, 100000000), ratio) + "亿";
    }
    if (len > 5) {
      return this.toFixed(MathUtil.divide(num, 100000), ratio) + "万";
    }

    return num;
  },

  /**
   * 获取百分比数据
   * @param num
   * @param ratio
   * @param percentFlag
   * @returns {string}
   */
  toFixedPercent(num, ratio = 2, percentFlag = true) {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }

    ratio = ratio < 0 ? 2 : ratio;
    return (
      this.toFixed(MathUtil.times(num, 100), ratio) + (percentFlag ? "%" : "")
    );
  },

  /**
   * 两个数的获取百分比数据
   * @param num1
   * @param num2
   * @param ratio
   * @param percentFlag
   * @returns {string}
   */
  toCompareFixedPercent(num1, num2, ratio = 2, percentFlag = true) {
    if (!CheckUtil.isLikeNumber(num1) || !CheckUtil.isLikeNumber(num2)) {
      return "";
    }

    ratio = ratio < 0 ? 2 : ratio;
    return (
      this.toFixed(MathUtil.times(MathUtil.divide(num1, num2), 100), ratio) +
      (percentFlag ? "%" : "")
    );
  },

  /**
   * 转换成金额千分位格式,数值为空不显示
   * @param num
   * @param ratio
   * @param currency
   * @param isZeroShowNull 数值为零时，显示为空
   * @returns {string|null}
   */
  toMoney(num, ratio = 2, currency = "¥", isZeroShowNull = false) {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }
    if (isZeroShowNull && parseFloat(num) === 0) {
      return null;
    }
    const sign = num < 0 ? "-" : "";
    const re = /(\d{3})(?=\d)/g;
    ratio = ratio < 0 ? 2 : ratio;
    currency = currency ? currency : "";
    const stringIfIed = this.toFixed(Math.abs(num), ratio);
    const _int = ratio ? stringIfIed.slice(0, -1 - ratio) : stringIfIed;
    const i = _int.length % 3;
    const head =
      i > 0 ? _int.toString().slice(0, i) + (_int.length > 3 ? "," : "") : "";
    const _float = ratio ? stringIfIed.slice(-1 - ratio) : "";
    return (
      currency +
      sign +
      head +
      _int.toString().slice(i).replace(re, "$1,") +
      _float
    );
  },

  /**
   * 转换成千分位格式,数值为空不显示，Number.prototype.toLocaleString() 可以转千分位
   * @param num
   * @param ratio
   * @param currency
   * @param isZeroShowNull 数值为零时，显示为空
   * @returns {string|null}
   */
  toMillennials(num, ratio = 2, isZeroShowNull = false) {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }
    if (isZeroShowNull && parseFloat(num) === 0) {
      return null;
    }

    // 使用 toLocaleString 的第二个参数来控制小数位数
    return Number(num).toLocaleString("en-US", {
      minimumFractionDigits: ratio,
      maximumFractionDigits: ratio,
    });
  },

  /**
   * 将数值转换为 % 显示
   * @param num
   * @param ratio
   * @returns {string|number}
   */
  toPercentage(num, ratio = 2) {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }

    num = parseFloat(num);
    if (num === 0) {
      return 0;
    }

    return this.toFixed(num * 100, ratio) + "%";
  },

  /**
   * 金额转换成中文大写格式
   * @param num
   * @param prefix
   * @returns {string}
   */
  toDigitUppercase(num, prefix = "大写金额：") {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }

    const fraction = ["角", "分"];
    const digit = ["零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"];
    const unit = [
      ["圆", "万", "亿"],
      ["", "拾", "佰", "仟"],
    ];
    let n = Math.abs(num);
    let s = "";
    fraction.forEach((item, index) => {
      s += (digit[Math.floor(n * 10 * 10 ** index) % 10] + item).replace(
        /零./,
        ""
      );
    });

    s = s || "整";
    n = Math.floor(num);
    for (let i = 0; i < unit[0].length && n > 0; i++) {
      let p = "";
      for (let j = 0; j < unit[1].length && n > 0; j++) {
        p = digit[n % 10] + unit[1][j] + p;
        n = Math.floor(n / 10);
      }
      s = p.replace(/(零.)*零$/, "").replace(/^$/, "零") + unit[0][i] + s;
    }

    return (
      prefix +
      s
        .replace(/(零.)*零圆/, "圆")
        .replace(/(零.)+/g, "零")
        .replace(/^整$/, "零圆整")
    );
  },

  /**
   * 金额转换成英文大写格式
   * @returns {string}
   * @param num
   */
  toDigitUppercaseEn(num) {
    const units = [
      "ZERO",
      "ONE",
      "TWO",
      "THREE",
      "FOUR",
      "FIVE",
      "SIX",
      "SEVEN",
      "EIGHT",
      "NINE",
    ];
    const teens = [
      "TEN",
      "ELEVEN",
      "TWELVE",
      "THIRTEEN",
      "FOURTEEN",
      "FIFTEEN",
      "SIXTEEN",
      "SEVENTEEN",
      "EIGHTEEN",
      "NINETEEN",
    ];
    const tens = [
      "",
      "",
      "TWENTY",
      "THIRTY",
      "FORTY",
      "FIFTY",
      "SIXTY",
      "SEVENTY",
      "EIGHTY",
      "NINETY",
    ];
    const thousands = [
      "",
      "THOUSAND",
      "MILLION",
      "BILLION",
      "TRILLION",
      "QUADRILLION",
    ];

    function convertChunk(n) {
      if (n < 10) return units[n];
      else if (n < 20) return teens[n - 10];
      else if (n < 100)
        return (
          tens[Math.floor(n / 10)] + (n % 10 !== 0 ? " " + units[n % 10] : "")
        );
      else {
        let chunk = "";
        let h = Math.floor(n / 100);
        let r = n % 100;
        if (h > 0) chunk += units[h] + " HUNDRED";
        if (r > 0) chunk += (chunk ? " AND " : "") + convertChunk(r);
        return chunk;
      }
    }

    function convertNumber(n) {
      if (n === 0) return "ZERO";
      let words = [];
      let i = 0;
      while (n > 0) {
        let rem = n % 1000;
        n = Math.floor(n / 1000);
        if (rem > 0) {
          words.unshift(
            convertChunk(rem) + (thousands[i] ? " " + thousands[i] : "")
          );
        }
        i++;
      }
      return words.join(" ");
    }

    // Split the number into integer and decimal parts
    let [integerPart, decimalPart] = num.toString().split(".");
    integerPart = parseInt(integerPart, 10);
    decimalPart = parseInt(decimalPart, 10);

    return (
      "TOTAL " +
      (
        convertNumber(integerPart) +
        (decimalPart ? " AND POINT " + convertNumber(decimalPart) : "")
      ).trim() +
      " ONLY"
    );
  },

  /**
   * 金额转换成中文数值格式
   * @param num
   * @returns {string}
   */
  toCnDigit(num) {
    const numChar = [
      "零",
      "一",
      "二",
      "三",
      "四",
      "五",
      "六",
      "七",
      "八",
      "九",
    ];
    const numUnit = ["", "十", "百", "千"]; // 权位
    const numSection = ["", "万", "亿", "万亿", "亿亿"]; // 节权位
    // 四位及以下数值转化为中文数值显示
    const formatSection = (num) => {
      const arr = (num + "").split("").reverse();
      let str = "";
      for (let i = 0, len = arr.length; i < len; i++) {
        // 将0-9转化为零到九
        const char = arr[i] === 0 ? numChar[0] : numChar[arr[i]] + numUnit[i]; // 当数字为0时不加权位，非零加权位
        str = char + str;
      }
      return str.replace(/零+/g, "零").replace(/零+$/, ""); // 将多个零合并为一个零，并剔除尾端的零
    };

    const arr = StringUtil.chunk(`${num}`, 4); // 将数字每四个拆分一次
    const list = [];
    for (let i = 0, len = arr.length; i < len; i++) {
      const str = formatSection(arr[i]);
      list.push(str);
    }
    const reverseList = list.reverse();
    for (let j = 0; j < reverseList.length; j++) {
      reverseList[j] += numSection[j];
    }
    return reverseList.reverse().join("");
  },

  /**
   * 金额转换成中文单位
   * @param num
   * @returns {string}
   * 1 => 元
   * 10000 => 万元
   */
  toDigit(num) {
    if (!CheckUtil.isLikeNumber(num)) {
      return "";
    }

    return (
      {
        1: "元",
        10: "十元",
        100: "百元",
        1000: "千元",
        10000: "万元",
        100000: "十万元",
        1000000: "百万元",
        10000000: "千万元",
        100000000: "亿元",
      }[num] || "元"
    );
  },
};
